/**************************************************************/
/*  This file is licensed from, and is a trade secret of:     */
/*                                                            */
/*    Mercury Computer Systems, Incorporated                  */
/*    199 Riverneck Road                                      */
/*    Chelmsford, Massachusetts 01824-2820                    */
/*    United States of America                                */
/*    Telephone + 1 978 256-1300                              */
/*                                                            */
/*  Refer to your Software License Agreement for provisions   */
/*  on use, duplication, or disclosure.                       */
/*  US. Government users and prime contractors are also       */
/*  governed by the following Data Rights Notice:             */
/*  Use, duplication or disclosure by the US. Government is   */
/*  subject to the provisions set forth in FAR 52.227-14 for  */
/*  restricted rights or other agency data rights provisions  */
/*  on commercial software and documentation, as applicable.  */
/*                                                            */
/*  This file: (a) was developed at private expense, and no   */
/*  part was developed with government funds, (b) is a        */
/*  trade secret of Mercury Computer Systems, Inc. for the    */
/*  purposes of the Freedom of Information Act, (c) is        */
/*  "commercial computer software" subject to limited         */
/*  utilization as provided in the above noted Software       */
/*  License Agreement and (d) is in all respects data         */
/*  belonging exclusively to Mercury Computer Systems, Inc..  */
/*                                                            */
/**************************************************************/

/******************************************************************/
/* Copyright (c) 1999-2003, Mercury Computer Systems, Inc.,       */
/* Chelmsford MA.,and all third party embedded software sources.  */
/* All rights reserved under the Copyright laws of US. and        */
/* international treaties.                                        */
/*                                                                */
/* Patent Pending                                                 */
/******************************************************************/


//$COPYRIGHT_END


#include "AudioPort_impl.h"

/*
 * ----------------------------------------------------------------------
 * Char port implementations.
 * ----------------------------------------------------------------------
 */

CharInPort_impl::CharInPort_impl (unsigned int max_data_size) 
  : m_already_connected (false),
    m_buffer_ready_sem (1),
    m_data_ready_sem (0),
    m_max_data_size (max_data_size),
    m_data_count (0)
{
  m_data_ptr = new char [m_max_data_size];
  m_input_ptr = m_data_ptr;
  m_read_ptr = m_data_ptr;
}

CharInPort_impl::~CharInPort_impl()
{
  delete m_data_ptr;
}

CORBA::Object_ptr
CharInPort_impl::getPort ()
  throw (CORBA::SystemException,
	 CF::PortSupplier::UnknownPort)
{
  return _this ();
} // End of CharInPort_impl::getPort()

void 
CharInPort_impl::push_char (const MC_SCA_CF::CharSequence & in_buffer)
  throw (CORBA::SystemException)
{
  unsigned int ii, timeout=0;

  // waiting for data buffer
  bool buffer_ready;

  do {
    buffer_ready = m_buffer_ready_sem.wait (100);
    timeout++;
  } while ((timeout < 5) && !buffer_ready);

  if (!buffer_ready) {
    // timeout
#ifdef MCS_VERBOSE
    cout << "CharInPort_impl: Error: Timeout waiting for data buffer." << endl;
#endif
    throw "CharInPort_impl::push_char::Timeout waiting for Data buffer";
  }

  unsigned int sampleCount = in_buffer.length();

  //  assert (m_data_count <= m_max_data_size);

  if (sampleCount > m_max_data_size-m_data_count) {
#ifdef MCS_VERBOSE
    cout << "CharInPort_impl: Error: Buffer not big enough for data." << endl;
#endif
    throw "CharInPort_impl::push_char::Data buffer not big enough for data xfer request";
  }

  // Fill buffer with data
  for (ii=0; ii<sampleCount; ii++) {
    *m_input_ptr++ = in_buffer[ii];
  }

  m_data_count += sampleCount;
  m_data_ready_sem.post();
} // End of CharInPort_impl::push_char()

unsigned int
CharInPort_impl::GetData (char ** buffer)
{
  bool data_ready = m_data_ready_sem.wait (100);

  if (!data_ready) { // timeout
    return 0;
  }

  *buffer = m_data_ptr;
  return m_data_count;
} // End of CharInPort_impl::GetData(char **buffer)

void
CharInPort_impl::ReleaseDataBuffer (int num_read)
{
  /*
   * Check to see if all the data was read from the buffer.
   */

  if (num_read == (int) m_data_count || num_read == -1) {
    // All the data has been read.
    m_data_count = 0;
    m_input_ptr = m_data_ptr;
  }
  else if (num_read == 0) {
    // None of the data has been read.
  }
  else {
    /*
     * Some of the data has been read. Move residual data to beginning
     * of buffer.
     */

    assert (num_read > 0);
    assert (m_data_count >= (unsigned int) num_read);
    m_data_count -= num_read;
    m_input_ptr = m_data_ptr + m_data_count;
    memmove (m_data_ptr, m_data_ptr+num_read, m_data_count);
  }

  m_buffer_ready_sem.post ();
} // End of CharInPort_impl::ReleaseDataBuffer()

CharOutPort_impl::CharOutPort_impl (char * out_buf,
				    unsigned long max_data_size)
  : m_remote_port (0),
    m_already_connected (false),
    m_previous_data_length (max_data_size)
{
  m_out_data = new MC_SCA_CF::CharSequence (max_data_size,
					    max_data_size, 
					   (CORBA::Octet *) out_buf);
} // End of CharOutPort_impl(char *out_buf, unsigned long max_data_size)

CharOutPort_impl::~CharOutPort_impl()
{
  delete m_out_data;
}

void
CharOutPort_impl::pushData (char * cbuffer, unsigned long SampleCount)
{
  // The specified length must be less than the allocated buffer size.
  if (SampleCount > m_out_data->maximum()) {
#ifdef MCS_VERBOSE
    cout << "CharOutPort_impl: Error: Too much data for output port." << endl;
#endif
    throw "CharOutPort_impl::pushData::Data output size too big";
  }

  // If the buffer address is different, we need to change it in the sequence.
  if (cbuffer != (char *) m_out_data->get_buffer()) {
    unsigned long max = m_out_data->maximum ();
    m_out_data->replace ((CORBA::ULong)max, (CORBA::ULong) SampleCount, 
			 (CORBA::Octet *) cbuffer, (CORBA::Boolean) 0);
    m_previous_data_length = SampleCount;
  }
  // If only the data length is different, we need to change it in the sequence.
  else if (SampleCount != m_previous_data_length) {
    m_out_data->length (SampleCount);
    m_previous_data_length = SampleCount;
  }

  m_remote_port->push_char (*m_out_data);
} // End of CharOutPort_impl::pushData();

CORBA::Object_ptr
CharOutPort_impl::getPort()
  throw (CORBA::SystemException,
	 CF::PortSupplier::UnknownPort)
{
  return _this ();
} // End of CharOutPort_impl::getPort()

void
CharOutPort_impl::connectPort (CORBA::Object_ptr connecting_port,
			       const CORBA::Char * connectionId)
  throw (CORBA::SystemException,
	 CF::Port::InvalidPort, 
	 CF::Port::OccupiedPort)
{
  if (m_already_connected) {
    throw CF::Port::OccupiedPort ();
  }

  try {
    m_remote_port = MC_SCA_CF::DataPortChar::_narrow (connecting_port);
  }
  catch (...) {
    throw CF::Port::InvalidPort ();
  }

  if (CORBA::is_nil (m_remote_port)) {
    throw CF::Port::InvalidPort ();
  }

  m_already_connected = true;
}  // End of CharOutPort_impl::connectPort(... )

/*
 * ----------------------------------------------------------------------
 * Short integer port implementations.
 * ----------------------------------------------------------------------
 */

ShortInPort_impl::ShortInPort_impl (unsigned int max_data_size) 
  : m_already_connected (false),
    m_buffer_ready_sem (1),
    m_data_ready_sem (0),
    m_data_count (0),
    m_max_data_size (max_data_size)
{
  m_data_ptr = new short [m_max_data_size];
  m_input_ptr = m_data_ptr;
  m_read_ptr = m_data_ptr;
}

ShortInPort_impl::~ShortInPort_impl()
{
  delete m_data_ptr;
}

unsigned int
ShortInPort_impl::GetData (short ** buffer)
{
  bool data_ready = m_data_ready_sem.wait (100);

  if (!data_ready) {// timeout
    return 0;
  }

  *buffer = m_data_ptr;
  return m_data_count;
} // End of ShortInPort_impl::GetData(char **buffer)

void
ShortInPort_impl::ReleaseDataBuffer (int num_read)
{
  /*
   * Check to see if all the data was read from the buffer.
   */

  if (num_read == (int) m_data_count || num_read == -1) {
    // All the data has been read.
    m_data_count = 0;
    m_input_ptr = m_data_ptr;
  }
  else if (num_read == 0) {
    // None of the data has been read.
  }
  else {
    /*
     * Some of the data has been read. Move residual data to beginning
     * of buffer.
     */

    assert (num_read > 0);
    assert (m_data_count >= (unsigned int) num_read);
    m_data_count -= num_read;
    m_input_ptr = m_data_ptr + m_data_count;
    memmove (m_data_ptr, m_data_ptr+num_read, m_data_count);
  }

  m_buffer_ready_sem.post ();
} // End of ShortInPort_impl::ReleaseDataBuffer()

CORBA::Object_ptr
ShortInPort_impl::getPort ()
  throw (CORBA::SystemException,
	 CF::PortSupplier::UnknownPort)
{
  return _this();
} // End of ShortInPort_impl::getPort()

void
ShortInPort_impl::push_short (const MC_SCA_CF::ShortSequence & in_buffer)
  throw (CORBA::SystemException)
{
  bool buffer_ready = m_buffer_ready_sem.wait (1000);

  if (!buffer_ready) {
    // Timeout.
#ifdef MCS_VERBOSE
    cout << "ShortInPort_impl: Error: Timeout waiting for data buffer." << endl;
#endif
    throw "ShortInPort_impl::push_short::Timeout waiting for Data buffer";
  }

  unsigned int sampleCount = in_buffer.length();

  if (sampleCount > m_max_data_size-m_data_count) {
#ifdef MCS_VERBOSE
    cout << "ShortInPort_impl: Error: Buffer not big enough for data." << endl;
#endif
    throw "ShortInPort_impl::push_short::Data buffer not big enough for data xfer request";
  }

  // Fill buffer with data
  for (unsigned int ii=0; ii<sampleCount; ii++) {
    *m_input_ptr++ = in_buffer[ii];
  }

  m_data_count += sampleCount;
  m_data_ready_sem.post();
} // End of ShortInPort_impl::push_short(const ShortSequence &in_buffer)

ShortOutPort_impl::ShortOutPort_impl (short * out_buf,
				      unsigned long max_data_size)
  : m_remote_port (0),
    m_already_connected (false),
    m_previous_data_length (max_data_size)
{
  m_out_data = new MC_SCA_CF::ShortSequence (max_data_size,
					     max_data_size, 
					     (CORBA::Short *) out_buf);
} // End of ShortOutPort_impl(char *out_buf, unsigned long max_data_size);

ShortOutPort_impl::~ShortOutPort_impl()
{
  delete m_out_data;
}

void
ShortOutPort_impl::pushData (short * out_buffer, unsigned long SampleCount)
{
  // The specified length must be less than the allocated buffer size.
  if (SampleCount > m_out_data->maximum()) {
#ifdef MCS_VERBOSE
    cout << "ShortOutPort_impl: Error: Too much data for output port." << endl;
#endif
    throw "ShortOutPort_impl::pushData::Data output size too big";
  }

  // If the buffer address is different, we need to change it in the sequence.
  if (out_buffer != (short *) m_out_data->get_buffer()) {
    unsigned long max = m_out_data->maximum();
    m_out_data->replace ((CORBA::ULong) max, (CORBA::ULong) SampleCount, 
			 (CORBA::Short *) out_buffer, (CORBA::Boolean) 0);
    m_previous_data_length = SampleCount;
  }
  // If only the data length is different, we need to change it in the sequence.
  else if (SampleCount != m_previous_data_length) {
    m_out_data->length (SampleCount);
    m_previous_data_length = SampleCount;
  }

  m_remote_port->push_short (*m_out_data);
} // End of ShortOutPort_impl::pushData();

CORBA::Object_ptr
ShortOutPort_impl::getPort ()
  throw (CORBA::SystemException,
	 CF::PortSupplier::UnknownPort)
{
  return _this ();

} // End of ShortOutPort_impl::getPort()

void
ShortOutPort_impl::connectPort (CORBA::Object_ptr connecting_port,
				const CORBA::Char * connectionId)
  throw (CORBA::SystemException,
	 CF::Port::InvalidPort, 
	 CF::Port::OccupiedPort)
{
  if (m_already_connected) {
    throw CF::Port::OccupiedPort ();
  }
  try {
    m_remote_port = MC_SCA_CF::DataPortShort::_narrow (connecting_port);
  }
  catch ( ... ) {
    throw CF::Port::InvalidPort();
  }

  if (CORBA::is_nil (m_remote_port)) {
    throw CF::Port::InvalidPort();
  }

  m_already_connected = true;
}  // End of ShortOutPort_impl::connectPort(... )

/*
 * ----------------------------------------------------------------------
 * Complex short integer port implementations.
 * ----------------------------------------------------------------------
 */

ComplexShortInPort_impl::ComplexShortInPort_impl (unsigned int max_data_size) 
  : m_already_connected (false),
    m_buffer_ready_sem (1),
    m_data_ready_sem (0),
    m_max_data_size (max_data_size),
    m_data_count (0)
{
  m_data_ptr = new CMPLX_INT16 [m_max_data_size];
  m_input_ptr = m_data_ptr;
  m_read_ptr = m_data_ptr;
}

ComplexShortInPort_impl::~ComplexShortInPort_impl()
{
  delete m_data_ptr;
}

CORBA::Object_ptr
ComplexShortInPort_impl::getPort ()
  throw (CORBA::SystemException,
	 CF::PortSupplier::UnknownPort)
{
  return _this();
} // End of ComplexShortInPort_impl::getPort()

void
ComplexShortInPort_impl::push_complexShort (const MC_SCA_CF::ComplexShortSequence & in_buffer)
  throw (CORBA::SystemException)
{
  unsigned int ii;

  // Waitfor data buffer.
  bool buffer_ready = m_buffer_ready_sem.wait (1000);

  if (!buffer_ready) {
    // Timeout.
#ifdef MCS_VERBOSE
    cout << "ComplexShortInPort_impl: Error: Timeout waiting for data buffer." << endl;
#endif
    throw "ComplexShortInPort_impl::push_complexShort::Timeout waiting for Data buffer";
  }

  unsigned int sampleCount = in_buffer.length();

  if (sampleCount > m_max_data_size-m_data_count) {
#ifdef MCS_VERBOSE
    cout << "ComplexShortInPort_impl: Error: Buffer not big enough for data." << endl;
#endif
    throw "ComplexShortInPort_impl::push_complexShort::Data buffer not big enough for data xfer request";
  }

  // Fill buffer with data.
  for (ii=0; ii<sampleCount; ii++) {
    *m_input_ptr++ = CMPLX_INT16 (in_buffer[ii].real, in_buffer[ii].imag);
  }

  m_data_count += sampleCount;

  // Indicate that the data is ready.
  m_data_ready_sem.post();
} // End of ComplexShortInPort_impl::push_complexShort(const MC_SCA_CF::ComplexShortSequence &in_buffer)

unsigned int
ComplexShortInPort_impl::GetData (CMPLX_INT16 ** buffer)
{
  bool data_ready = m_data_ready_sem.wait (100);

  // Timeout if nothing is ready to check for stop command.
  if (!data_ready) {
    return 0;
  }

  *buffer = m_data_ptr;
  return m_data_count;
} // End of ComplexShortInPort_impl::GetData(CMPLX_INT16 **buffer)

void
ComplexShortInPort_impl::ReleaseDataBuffer (int num_read)
{
  /*
   * Check to see if all the data was read from the buffer.
   */

  if (num_read == (int) m_data_count || num_read == -1) {
    // All the data has been read.
    m_data_count = 0;
    m_input_ptr = m_data_ptr;
  }
  else if (num_read == 0) {
    // None of the data has been read.
  }
  else {
    /*
     * Some of the data has been read. Move residual data to beginning
     * of buffer.
     */

    assert (num_read > 0);
    assert (m_data_count >= (unsigned int) num_read);
    m_data_count -= num_read;
    m_input_ptr = m_data_ptr + m_data_count;
    memmove (m_data_ptr, m_data_ptr+num_read, m_data_count);
  }

  m_buffer_ready_sem.post ();
} // End of ComplexShortInPort_impl::ReleaseDataBuffer()

ComplexShortOutPort_impl::ComplexShortOutPort_impl (CMPLX_INT16 * out_buf,
						    unsigned long max_data_size)
  : m_remote_port (0),
    m_already_connected (false),
    m_previous_data_length (max_data_size)
{
  m_out_data = 
    new MC_SCA_CF::ComplexShortSequence (max_data_size, max_data_size, 
					 (MC_SCA_CF::ComplexShort *) out_buf);
}

ComplexShortOutPort_impl::~ComplexShortOutPort_impl ()
{
  delete m_out_data;
}

void
ComplexShortOutPort_impl::pushData (CMPLX_INT16 * cbuffer,
				    unsigned long SampleCount)
{
  // The specified length must be less than the allocated buffer size.
  if (SampleCount > m_out_data->maximum()) {
#ifdef MCS_VERBOSE
    cout << "ComplexShortOutPort_impl: Error: Too much data for output port." << endl;
#endif
    throw "ComplexShortOutPort_impl::pushData::Data output size too big";
  }

  // If the buffer address is different, we need to change it in the sequence.
  if (cbuffer != (CMPLX_INT16 *) m_out_data->get_buffer()) {
    unsigned long max = m_out_data->maximum();
    m_out_data->replace ((CORBA::ULong) max, (CORBA::ULong) SampleCount, 
			 (MC_SCA_CF::ComplexShort *) cbuffer, 
			 (CORBA::Boolean) 0);
    m_previous_data_length = SampleCount;
  }
  // If only the data length is different, we need to change it in the sequence.
  else if (SampleCount != m_previous_data_length) {
    m_out_data->length (SampleCount);
    m_previous_data_length = SampleCount;
  }

  m_remote_port->push_complexShort (*m_out_data);
} // End of ComplexShortOutPort_impl::pushData();

CORBA::Object_ptr
ComplexShortOutPort_impl::getPort ()
  throw (CORBA::SystemException,
	 CF::PortSupplier::UnknownPort)
{
  return _this();
} // End of ComplexShortOutPort_impl::getPort()

void
ComplexShortOutPort_impl::connectPort (CORBA::Object_ptr connecting_port,
				       const CORBA::Char* connectionId)
  throw (CORBA::SystemException,
	 CF::Port::InvalidPort, 
	 CF::Port::OccupiedPort)
{
  if (m_already_connected) {
    throw CF::Port::OccupiedPort ();
  }
  try {
    m_remote_port = MC_SCA_CF::DataPortComplexShort::_narrow (connecting_port);
  }
  catch (...) {
    throw CF::Port::InvalidPort ();
  }

  if (CORBA::is_nil (m_remote_port)) {
    throw CF::Port::InvalidPort ();
  }

  m_already_connected = true;
}  // End of ComplexShortOutPort_impl::connectPort(... )

